#include "mf_spi.h"
#include <string.h>

#if !MF_SPI1_DMA_ONLY_USE_TX
static FL_ITStatus spi_dma_complete;
#endif

/**
 * @brief  SPI1 Initialization function
 * @param  void
 * @retval None
 */
void mf_spi_init(void)
{
    FL_GPIO_InitTypeDef GPIO_InitStruct;

    FL_SPI_InitTypeDef SPI1_InitStruct;

    /* PB3 SPI1_DIS */
    GPIO_InitStruct.pin = FL_GPIO_PIN_3;
    GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* PB8 SPI1_CS */
    GPIO_InitStruct.pin = FL_GPIO_PIN_8;
    GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* PB9 SPI1_SCK */
    GPIO_InitStruct.pin = FL_GPIO_PIN_9;
    GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* PB10 SPI1_MISO */
    GPIO_InitStruct.pin = FL_GPIO_PIN_10;
    GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* PB11 SPI1_MOSI */
    GPIO_InitStruct.pin = FL_GPIO_PIN_11;
    GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    SPI1_InitStruct.transferMode = FL_SPI_TRANSFER_MODE_FULL_DUPLEX;
    SPI1_InitStruct.mode = FL_SPI_WORK_MODE_MASTER;
    SPI1_InitStruct.dataWidth = FL_SPI_DATA_WIDTH_8B;
    SPI1_InitStruct.clockPolarity = FL_SPI_POLARITY_NORMAL;
    SPI1_InitStruct.clockPhase = FL_SPI_PHASE_EDGE1;
    SPI1_InitStruct.softControl = FL_DISABLE;
    SPI1_InitStruct.baudRate = FL_SPI_BAUDRATE_DIV4; /* FAPBCLK/4 -> 64Mhz/4=16Mhz */
    SPI1_InitStruct.bitOrder = FL_SPI_BIT_ORDER_LSB_FIRST;

    FL_SPI_Init(MF_SPI1_BASE, &SPI1_InitStruct);

    mf_spi_dma_init();
}

/**
 * @brief  DMA_Channel6 Initialization function
 * @param  void
 * @retval FL_ErrorStatus
 */
FL_ErrorStatus mf_spi_dma_init(void)
{
    FL_ErrorStatus ret = FL_PASS;
    FL_DMA_InitTypeDef DMA_InitStruct;

    DMA_InitStruct.periphAddress = MF_SPI1_DMA_PERIPH_ADDRESS;
    DMA_InitStruct.direction = FL_DMA_DIR_RAM_TO_PERIPHERAL;
    DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;
    DMA_InitStruct.flashAddressIncMode = FL_DMA_FLASH_INC_MODE_INCREASE;
    DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_8B;
    DMA_InitStruct.priority = FL_DMA_PRIORITY_LOW;
    DMA_InitStruct.circMode = FL_DISABLE;
    ret &= FL_DMA_Init(MF_SPI1_DMA_BASE, &DMA_InitStruct, MF_SPI1_DMA_TX_CHANNEL);

#if !MF_SPI1_DMA_ONLY_USE_TX
    DMA_InitStruct.periphAddress = FL_DMA_PERIPHERAL_FUNCTION1;
    DMA_InitStruct.direction = FL_DMA_DIR_PERIPHERAL_TO_RAM;
    DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;
    DMA_InitStruct.flashAddressIncMode = FL_DMA_FLASH_INC_MODE_INCREASE;
    DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_8B;
    DMA_InitStruct.priority = FL_DMA_PRIORITY_LOW;
    DMA_InitStruct.circMode = FL_DISABLE;
    ret &= FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_5);
#endif

    return ret;
}

/**
 * @brief mf_spi_write
 * @param *data
 * @param length
 * @retval None
 */
void mf_spi_write(uint8_t *data, uint16_t length)
{
    while (length--)
    {
        FL_SPI_WriteTXBuff(MF_SPI1_BASE, *data);
        data++;
        while (!(FL_SPI_IsActiveFlag_TXBuffEmpty(MF_SPI1_BASE)))
            ;
    }
}

/**
 * @brief mf_spi_dma_data_addr
 * @param *data_param
 * @return FL_ErrorStatus
 */
#if MF_SPI1_DMA_ONLY_USE_TX
static FL_ErrorStatus mf_spi_dma_conf(uint8_t *w_buff, uint16_t length)
{
    FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};

    while (FL_SPI_IsActiveFlag_Busy(MF_SPI1_BASE))
    {
        /* code */
    }

    // while (!FL_DMA_IsActiveFlag_TransferComplete(MF_SPI1_DMA_BASE, MF_SPI1_DMA_TX_CHANNEL))
    // {
    // }
    // FL_DMA_ClearFlag_TransferComplete(MF_SPI1_DMA_BASE, MF_SPI1_DMA_TX_CHANNEL);

    FL_SPI_Disable(MF_SPI1_BASE);    /* Disable SPI1 */
    FL_DMA_Enable(MF_SPI1_DMA_BASE); /* Enable DMA */

    DMA_ConfigStruct.memoryAddress = (uint32_t)w_buff;                                     /* set str base_address */
    DMA_ConfigStruct.transmissionCount = length - 1;                                       /* set dma request_num */
    FL_DMA_StartTransmission(MF_SPI1_DMA_BASE, &DMA_ConfigStruct, MF_SPI1_DMA_TX_CHANNEL); /* start request_num */

    FL_SPI_Enable(MF_SPI1_BASE); /* Enable SPI1 */

    return FL_PASS;
}
#else
static FL_ErrorStatus mf_spi_dma_conf(uint8_t *w_buff, uint8_t *r_buff, uint16_t length)
{
    FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};

    FL_SPI_Disable(MF_SPI1_BASE);    /* Disable SPI1 */
    FL_DMA_Enable(MF_SPI1_DMA_BASE); /* Enable DMA */

    DMA_ConfigStruct.memoryAddress = (uint32_t)w_buff;                                           /* set str base_address */
    DMA_ConfigStruct.transmissionCount = length - 1;                                             /* set dma request_num */
    (void)FL_DMA_StartTransmission(MF_SPI1_DMA_BASE, &DMA_ConfigStruct, MF_SPI1_DMA_TX_CHANNEL); /* start request_num */

    DMA_ConfigStruct.memoryAddress = (uint32_t)r_buff;                                           /* set str base_address */
    DMA_ConfigStruct.transmissionCount = length - 1;                                             /* set dma request_num */
    (void)FL_DMA_StartTransmission(MF_SPI1_DMA_BASE, &DMA_ConfigStruct, MF_SPI1_DMA_TX_CHANNEL); /* start request_num */

    FL_DMA_ClearFlag_TransferComplete(MF_SPI1_DMA_BASE, MF_SPI1_DMA_TX_CHANNEL); /* Clear flag */
    FL_DMA_EnableIT_TransferComplete(MF_SPI1_DMA_BASE, MF_SPI1_DMA_TX_CHANNEL);  /* Enable dma IT */

    FL_SPI_Enable(MF_SPI1_BASE); /* Enable SPI1 */

    return FL_PASS;
}
#endif

#if MF_SPI1_DMA_ONLY_USE_TX
/**
 * @brief uart0_dma_trans
 * @param *w_buff
 * @param length
 * @return None
 */
void spi1_dma_trans(uint8_t *w_buff, uint16_t length)
{
    mf_spi_dma_conf(w_buff, length);
}
#else
/**
 * @brief uart0_dma_trans
 * @param *w_buff
 * @param *r_buff
 * @param length
 * @return None
 */
void spi1_dma_trans(uint8_t *w_buff, uint8_t *r_buff, uint16_t length)
{
    if (spi_dma_complete == FL_SET)
    {
        spi_dma_complete = FL_RESET;
        mf_spi_dma_conf(w_buff, r_buff, length);
    }
}

/**
 * @brief mf_spi_dma_complete_flag
 * @param status
 * @return None
 */
void mf_spi_dma_complete_flag(FL_ITStatus status)
{
    spi_dma_complete = status;
}
#endif
